package com.evildog.workspace.system.application.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.evildog.workspace.common.object.PageQuery;
import com.evildog.workspace.common.result.PagedResult;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.evildog.workspace.dependencies.mybatis.base.TableLinkService;
import com.evildog.workspace.dependencies.mybatis.enums.BaseStatusEnum;
import com.evildog.workspace.dependencies.mybatis.object.BaseStatusDTO;
import com.evildog.workspace.dependencies.mybatis.object.QueryConditionDTO;
import com.evildog.workspace.dependencies.mybatis.util.BaseStatusValidate;
import com.evildog.workspace.dependencies.mybatis.util.QueryConditionUtils;
import com.evildog.workspace.system.application.bo.RoleBO;
import com.evildog.workspace.system.application.bo.RoleListBO;
import com.evildog.workspace.system.application.bo.RolePageBO;
import com.evildog.workspace.system.application.bo.RoleUiPermissionBO;
import com.evildog.workspace.system.application.convert.ComponentPermissionConvert;
import com.evildog.workspace.system.application.convert.MenuPermissionConvert;
import com.evildog.workspace.system.application.convert.RoleConvert;
import com.evildog.workspace.system.application.dto.RoleDTO;
import com.evildog.workspace.system.application.dto.RoleListDTO;
import com.evildog.workspace.system.application.dto.RolePageDTO;
import com.evildog.workspace.system.application.dto.RoleUpdateUiPermissionDTO;
import com.evildog.workspace.system.application.entity.*;
import com.evildog.workspace.system.application.mapper.ComponentPermissionMapper;
import com.evildog.workspace.system.application.mapper.MenuPermissionMapper;
import com.evildog.workspace.system.application.mapper.RoleMapper;
import com.evildog.workspace.system.application.mapper.UserUserGroupLinkMapper;
import com.evildog.workspace.system.application.service.*;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.*;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    private final UserUserGroupLinkMapper userUserGroupLinkMapper;

    private final RoleUserGroupLinkService roleUserGroupLinkService;
    private final RoleMenuPermissionLinkService roleMenuPermissionLinkService;
    private final RoleComponentPermissionLinkService roleComponentPermissionLinkService;

    private final UserGroupService userGroupService;
    private final MenuPermissionMapper menuPermissionMapper;
    private final ComponentPermissionMapper componentPermissionMapper;

    private final TableLinkService tableLinkService;


    @Override
    public PagedResult<RolePageBO> getPageList(PageQuery query, List<QueryConditionDTO> queryConditions, RolePageDTO pageDTO) {
        IPage<RolePageDO> page = this.baseMapper.getPageList(
                QueryConditionUtils.getPagination(query),
                queryConditions,
                pageDTO);
        return RoleConvert.INSTANCE.convert(page);
    }

    @Override
    public RoleBO getDetailById(Long id) {
        Role role = this.getById(id);
        Assert.notNull(role, "role is null!");
        return RoleConvert.INSTANCE.convert(role);
    }

    @Override
    public boolean save(RoleDTO dto) {
        Role newRole = RoleConvert.INSTANCE.convert(dto);
        return save(newRole);
    }

    @Override
    public boolean updateById(Long id, RoleDTO dto) {
        Role oldRole = getById(id);
        Assert.notNull(oldRole, "role is null!");
        Role newRole = RoleConvert.INSTANCE.convert(dto);
        newRole.setId(id);
        return updateById(newRole);
    }

    private List<Long> getUserRoleIds(Long userId) {
        // 用户组包含的权限
        List<Long> userGroupRoleIds = getRoleIdsOnUserGroups(userId);

        // 其他权限...

        List<Role> roles = getValidRolesByUserGroup(userGroupRoleIds);

        return roles.stream().map(Role::getId).collect(Collectors.toList());
    }

    private List<Role> getValidRolesByUserGroup(List<Long> userGroups) {

        List<Long> roleIds = tableLinkService.getLinkIdList(roleUserGroupLinkService,
                RoleUserGroupLink::getRoleId,
                RoleUserGroupLink::getUserGroupId, userGroups);

        return list(Wrappers.<Role>lambdaQuery()
                .select(Role::getId)
                .eq(Role::getStatus, BaseStatusEnum.IS_ABLE.getStatus())
                .in(Role::getId, roleIds)
        );

    }

    private List<Long> getRoleIdsOnUserGroups(Long userId) {
        List<Long> userGroupIds = tableLinkService.getLinkIdList(
                userUserGroupLinkMapper,
                UserUserGroupLink::getUserGroupId,
                UserUserGroupLink::getUserId, userId);

        List<UserGroup> userGroupList = tableLinkService.getLinkList(userGroupService, UserGroup::getId, userGroupIds);

        // 只需要可用的用户组
        List<Long> userGroups = userGroupList.stream()
                .filter(userGroup -> Objects.equals(userGroup.getStatus(), BaseStatusEnum.IS_ABLE.getStatus()))
                .map(UserGroup::getId)
                .collect(Collectors.toList());

        return tableLinkService.getLinkIdList(roleUserGroupLinkService,
                RoleUserGroupLink::getRoleId,
                RoleUserGroupLink::getUserGroupId, userGroups);
    }

    @Override
    public boolean updateStatus(Long id, BaseStatusDTO roleDTO) {
        Role oldRole = getById(id);
        Assert.notNull(oldRole, "role is null!");

        Integer status = roleDTO.getStatus();
        BaseStatusValidate.checkStatusValid(status);

        Role newRole = new Role()
                .setId(id)
                .setStatus(status);
        return updateById(newRole);
    }

    @Override
    public boolean remove(Long id) {
        if (removeById(id)) {
            // 删除与菜单的关联
            tableLinkService.removeByLinkId(roleMenuPermissionLinkService, RoleMenuPermissionLink::getRoleId, id);

            // 删除与组件的关联
            tableLinkService.removeByLinkId(roleComponentPermissionLinkService, RoleComponentPermissionLink::getRoleId, id);

            // 删除与用户组的关联
            tableLinkService.removeByLinkId(roleUserGroupLinkService, RoleUserGroupLink::getRoleId, id);
        }

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateUiPermissions(Long id, RoleUpdateUiPermissionDTO param) {

        Role oldRole = getById(id);
        Assert.notNull(oldRole, "role is null!");

        // 删除与菜单的关联
        tableLinkService.removeByLinkId(roleMenuPermissionLinkService, RoleMenuPermissionLink::getRoleId, id);

        // 删除与组件的关联
        tableLinkService.removeByLinkId(roleComponentPermissionLinkService, RoleComponentPermissionLink::getRoleId, id);

        List<Long> menuPermissions = param.getMenuPermissions();
        saveMenuPermissions(id, menuPermissions);


        List<Long> componentPermissions = param.getComponentPermissions();
        saveComponentPermissions(id, componentPermissions);

        return true;
    }

    @Override
    public RoleUiPermissionBO getAllUiPermissions(Long id) {
        List<MenuPermission> menuPermissions = getMenuPermissionsByRoleId(Collections.singletonList(id));
        List<ComponentPermission> componentPermissions = getComponentPermissionsByRoleId(Collections.singletonList(id));
        return new RoleUiPermissionBO()
                .setComponentPermissions(ComponentPermissionConvert.INSTANCE.convertBOList2(componentPermissions))
                .setMenuPermissions(MenuPermissionConvert.INSTANCE.convertBoList(menuPermissions))
                ;
    }

    @Override
    public List<MenuPermission> getMenuPermissions(Long userId) {
        List<Long> userRoleIds = getUserRoleIds(userId);
        return getMenuPermissionsByRoleId(userRoleIds);
    }


    /**
     * 查询角色关联的*可用*组件
     */
    @Override
    public List<ComponentPermission> getComponentPermissions(Long userId) {
        List<Long> userRoleIds = getUserRoleIds(userId);

        return getComponentPermissionsByRoleId(userRoleIds);
    }

    @Override
    public List<RoleListBO> getList(List<QueryConditionDTO> queryCondition, RoleListDTO dto) {
        List<RoleListDO> list = this.baseMapper.getList(queryCondition, dto);
        return RoleConvert.INSTANCE.convert(list);
    }

    @Override
    public List<RoleListBO> getUserRolesByUserGroup(Long userGroupId) {
        List<Role> validRoles = getValidRolesByUserGroup(Collections.singletonList(userGroupId));
        return RoleConvert.INSTANCE.convertBoList(validRoles);
    }

    /**
     * 查询出roleId关联的*可用*菜单权限
     *
     * @param userRoleIds 所有角色id
     */
    private List<MenuPermission> getMenuPermissionsByRoleId(List<Long> userRoleIds) {
        List<Long> menuPermissionIds = tableLinkService.getLinkIdList(
                roleMenuPermissionLinkService,
                RoleMenuPermissionLink::getMenuPermissionId,
                RoleMenuPermissionLink::getRoleId, userRoleIds
        );

        List<MenuPermission> menuPermissionList = tableLinkService.getLinkList(
                menuPermissionMapper,
                MenuPermission::getId, menuPermissionIds);

        return menuPermissionList.stream()
                .filter(menuPermission -> Objects.equals(menuPermission.getStatus(), BaseStatusEnum.IS_ABLE.getStatus()))
                .collect(Collectors.toList());
    }

    /**
     * 查询出roleId关联的*可用*组件权限
     *
     * @param userRoleIds 所有角色id
     */
    private List<ComponentPermission> getComponentPermissionsByRoleId(List<Long> userRoleIds) {
        List<Long> componentPermissionIds = tableLinkService.getLinkIdList(roleComponentPermissionLinkService,
                RoleComponentPermissionLink::getComponentPermissionId,
                RoleComponentPermissionLink::getRoleId, userRoleIds
        );

        List<ComponentPermission> componentPermissions = tableLinkService.getLinkList(
                componentPermissionMapper,
                ComponentPermission::getId, componentPermissionIds);

        return componentPermissions.stream()
                .filter(componentPermission -> Objects.equals(componentPermission.getStatus(), BaseStatusEnum.IS_ABLE.getStatus()))
                .collect(Collectors.toList());
    }

    private void saveComponentPermissions(Long roleId, List<Long> componentPermissions) {
        if (!componentPermissions.isEmpty()) {
            List<RoleComponentPermissionLink> links = new ArrayList<>();
            componentPermissions.forEach(linkId ->
                    links.add(new RoleComponentPermissionLink()
                            .setComponentPermissionId(linkId)
                            .setRoleId(roleId)
                    ));

            roleComponentPermissionLinkService.saveBatch(links);
        }
    }

    private void saveMenuPermissions(Long id, List<Long> menuPermissions) {
        if (!menuPermissions.isEmpty()) {
            List<RoleMenuPermissionLink> links = new ArrayList<>();
            menuPermissions.forEach(linkId ->
                    links.add(new RoleMenuPermissionLink()
                            .setRoleId(id)
                            .setMenuPermissionId(linkId)
                    ));

            roleMenuPermissionLinkService.saveBatch(links);
        }
    }
}
